package ltd.dujiabao.reserver.service;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;

import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import lombok.extern.slf4j.Slf4j;
import ltd.dujiabao.reserver.constant.RequestHeaderConstant;
import ltd.dujiabao.reserver.domain.LoginResult;
import ltd.dujiabao.reserver.util.FileUtils;
import ltd.dujiabao.reserver.util.HttpClientUtils;
import ltd.dujiabao.reserver.util.JsonUtils;
import ltd.dujiabao.reserver.util.StringUtils;

/**
 * @author : DuJiabao
 * @Project : reserver
 * @Time : 2021/11/5 21:57
 * @Desc : 登录服务
 */
@Slf4j
@Service
public class LoginService {
    @Value("${reserver.login.pageUrl}")
    public String loginPageUrl;

    @Value("${reserver.login.validationCodeUrl}")
    public String validationCodeUrl;

    @Value("${reserver.login.loginIntoUrl}")
    public String loginIntoUrl = "https://libyy.utsz.edu.cn/loginto.html";

    @Value("${reserver.login.usename}")
    public String username;

    @Value("${reserver.login.password}")
    public String password;

    /**
     * 打开页面，若请求头中无携带Cookie，会在响应的响应头中携带一个"Set-Cookie"。因此，将其取出并返回
     *
     * @return Cookie 可能返回空，需要判空
     */
    public String getCookie() {
        Map<String, String> headers = new HashMap<>(8);
        headers.put(RequestHeaderConstant.HEADER_NAME_ACCEPT, "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8");
        headers.put(RequestHeaderConstant.HEADER_NAME_ACCEPT_ENCODING, "gzip, deflate, br");
        headers.put(RequestHeaderConstant.HEADER_NAME_ACCEPT_LANGUAGE, "zh-CN,zh;q=0.9");
        headers.put(RequestHeaderConstant.HEADER_NAME_CONNECTION, "keep-alive");
        headers.put(RequestHeaderConstant.HEADER_NAME_CACHE_CONTROL, "max-age=0");
        //headers.put(RequestHeaderConstant.HEADER_NAME_HOST, "libyy.utsz.edu.cn");
        headers.put(RequestHeaderConstant.HEADER_NAME_UPGRADE_INSECURE_REQUESTS, "1");
        headers.put(RequestHeaderConstant.HEADER_NAME_USER_AGENT, "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3875.400 QQBrowser/10.8.4492.400");
        HttpResponse response = HttpClientUtils.doGet(loginPageUrl, headers);
        if (response != null) {
            Header[] setCookies = response.getHeaders("Set-Cookie");
            if (setCookies.length >= 1) {
                String cookie = setCookies[0].getValue();
                log.info("Getting cookie successfully, Cookie: {}.", cookie);
                return cookie;
            }
        }
        log.warn("Getting cookie fail.");
        return null;
    }

    /**
     * @param cookie cookie，由getCookie获取
     * @return true表示下载成功，false表示下载失败
     */
    public boolean downloadValidationCode(String cookie, String tempPath) {
        if (StringUtils.isNullOrEmpty(cookie)) {
            log.warn("Cookie cannot be null or empty when downloading validation code, or else it would to be useless.");
            return false;
        }

        Map<String, String> headers = new HashMap<>(8);
        headers.put(RequestHeaderConstant.HEADER_NAME_ACCEPT, "image/webp,image/apng,image/*,*/*;q=0.8");
        headers.put(RequestHeaderConstant.HEADER_NAME_ACCEPT_ENCODING, "gzip, deflate, br");
        headers.put(RequestHeaderConstant.HEADER_NAME_ACCEPT_LANGUAGE, "zh-CN,zh;q=0.9");
        headers.put(RequestHeaderConstant.HEADER_NAME_CONNECTION, "keep-alive");
        headers.put(RequestHeaderConstant.HEADER_NAME_COOKIE, cookie);
        //headers.put(RequestHeaderConstant.HEADER_NAME_HOST, "libyy.utsz.edu.cn");
        headers.put(RequestHeaderConstant.HEADER_NAME_REFERER, "https://libyy.utsz.edu.cn/login.html");
        headers.put(RequestHeaderConstant.HEADER_NAME_USER_AGENT, "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3875.400 QQBrowser/10.8.4492.400");
        HttpResponse response = HttpClientUtils.doGet(validationCodeUrl, headers);
        if (response != null) {
            boolean isSuccess = downFileFromResponse(response, tempPath);
            if (isSuccess) {
                log.info("Downloading validation code successfully, Path: {}", tempPath);
                return true;
            }
        }
        log.warn("Downloading validation code fail, Path: {}.", tempPath);
        return false;
    }

    /**
     * 执行登录操作
     *
     * @param cookie 在登录页面获取的cookie
     * @param code   获取到的验证码结果
     * @return true表示登录过程成功，false表示失败
     */
    public boolean doLogin(String cookie, String code) {
        if (StringUtils.isNullOrEmpty(cookie)) {
            log.warn("Cookie cannot be null or empty when login, or else you cannot login successfully.");
            return false;
        }

        if (StringUtils.isNullOrEmpty(code)) {
            log.warn("Code cannot be null or empty when login, or else you cannot login successfully.");
            return false;
        }

        Map<String, String> headers = new HashMap<>(11);
        //headers.put(RequestHeaderConstant.HEADER_NAME_HOST, "libyy.utsz.edu.cn");
        headers.put(RequestHeaderConstant.HEADER_NAME_CONNECTION, "keep-alive");
        headers.put(RequestHeaderConstant.HEADER_NAME_ACCEPT, "application/json, text/javascript, */*; q=0.01");
        headers.put(RequestHeaderConstant.HEADER_NAME_ORIGIN, "https://libyy.utsz.edu.cn");
        headers.put(RequestHeaderConstant.HEADER_NAME_X_REQUESTED_WITH, "XMLHttpRequest");
        headers.put(RequestHeaderConstant.HEADER_NAME_USER_AGENT, "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3875.400 QQBrowser/10.8.4492.400");
        headers.put(RequestHeaderConstant.HEADER_NAME_CONTENT_TYPE, "application/x-www-form-urlencoded; charset=UTF-8");
        headers.put(RequestHeaderConstant.HEADER_NAME_REFERER, "https://libyy.utsz.edu.cn/login.html");
        headers.put(RequestHeaderConstant.HEADER_NAME_ACCEPT_ENCODING, "gzip, deflate, br");
        headers.put(RequestHeaderConstant.HEADER_NAME_ACCEPT_LANGUAGE, "zh-CN,zh;q=0.9");
        headers.put(RequestHeaderConstant.HEADER_NAME_COOKIE, cookie);
        String params = "username=" + username + "&password=" + password + "&code=" + code;
        HttpResponse response = HttpClientUtils.doPost(loginIntoUrl + "?" + params, headers, null, Charset.defaultCharset());
        if (response != null) {
            try {
                String entity = EntityUtils.toString(response.getEntity());
                LoginResult loginResult = JsonUtils.json2bean(entity, LoginResult.class);
                Integer errorCode = loginResult.getError();
                switch (errorCode) {
                    case -1:
                        log.info("Login successfully, username: {}", username);
                        return true;
                    case 4:
                        log.info("Login fail, because of the wrong validation code, username: {}", username);
                        return false;
                    case 6:
                        log.info("Login fail, because of the wrong username or password, username: {}", username);
                        return false;
                    default:
                        log.info("Login fail, unknown reason, username: {}", username);
                        return false;
                }

            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        log.info("Login fail, username: {}", username);
        return false;
    }

    /**
     * 将响应携带的文件，下载到本地的操作
     *
     * @param response 响应
     * @param target   目标地址
     */
    private boolean downFileFromResponse(HttpResponse response, String target) {
        try (InputStream inputStream = response.getEntity().getContent()) {
            FileUtils.saveFile(inputStream, target);
            return true;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }
}
